home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Contrib / Socket / socket.c
Encoding:
C/C++ Source or Header  |  1995-02-05  |  7.2 KB  |  268 lines

  1. /*
  2.  * This file is a contribution of David Tolpin (dvd@pizza.msk.su)
  3.  * It is an implementation of BSD-INET sockets and is known to run on 
  4.  * Solaris 1 and Linux.
  5.  *
  6.  * (prepare-server-socket portnum) 
  7.  *  bound socket to a local address. Returns an object of type socket-handle
  8.  *
  9.  * (release-server-socket! handle) 
  10.  * close server socket (created by prepare-server-socket
  11.  * 
  12.  * (socket-handle? handle) 
  13.  * returns truth if the handle is of type socket-handle, false otherwise
  14.  * 
  15.  * (listen-socket! handle) 
  16.  * listen for connection requests 
  17.  * 
  18.  * (accept-connection handle) 
  19.  * returns a new socket in response to a detected connection request,
  20.  * the return value is a list of two ports, 
  21.  *      - (car sp) is opened for reading, 
  22.  *    - (cadr sp) - for writing
  23.  * 
  24.  * (open-client-socket hostname portnum) 
  25.  * connect to a socket on a remote machine, returns the same data structure
  26.  * as the function described above
  27.  *
  28.  * (shutdown-connection! skt)                            
  29.  * shutdown socket, the mode of shutting down is determined according to
  30.  * the mode of the port (read or write)
  31.  */
  32.  
  33. #include "stk.h"
  34. #include <errno.h>
  35. #include <sys/types.h>
  36. #include <sys/socket.h>
  37. #include <netinet/in.h>
  38. #include <netdb.h>
  39.  
  40. PRIMITIVE prepare_server_socket(SCM portnum);
  41. PRIMITIVE release_server_socket(SCM handle);
  42. PRIMITIVE socket_handlep(SCM handle);
  43. PRIMITIVE listen_socket(SCM handle);
  44. PRIMITIVE accept_connection(SCM handle);
  45. PRIMITIVE open_client_socket(SCM hostname, SCM portnum);
  46. PRIMITIVE shutdown_connection(SCM skt);
  47.  
  48. /*
  49. : stk_socket.c,v 1.4 1994/06/26 19:14:55 dvd Exp dvd $
  50. */
  51.  
  52. /*
  53. : stk_socket.c,v $
  54.  * Revision 1.4  1994/06/26  19:14:55  dvd
  55.  * *** empty log message ***
  56.  *
  57.  * Revision 1.3  1994/06/26  18:55:27  dvd
  58.  * Verbose error reporting is added
  59.  *
  60. */ 
  61.  
  62. #ifdef __sun__
  63. extern char *sys_errlist[];
  64. #endif
  65.  
  66. struct socket_handle {
  67.     int portnum;
  68.     char *hostname;
  69.     int handle;
  70. };
  71.  
  72. static int tc_sockhandle;
  73.  
  74. static void free_sockhandle(SCM handle);
  75. static void mark_sockhandle(SCM handle);
  76. static void displ_sockhandle(SCM x, FILE *f, int mode);
  77.  
  78. static extended_scheme_type sockhandle_type = {
  79.     "sockhandle",        /* name */
  80.     0,             /* is_procp */
  81.     mark_sockhandle,     /* gc_mark_fct */
  82.     free_sockhandle,    /* gc_free_fct */
  83.     NULL,            /* apply_fct */
  84.     displ_sockhandle    /* display_fct */
  85. };
  86.  
  87.  
  88. #define SOCKHANDLE(x)   ((struct socket_handle*)(x->storage_as.extension.data))
  89. #define LSOCKHANDLE(x)  (x->storage_as.extension.data)
  90. #define SOCKHANDLEP(x)  (TYPEP(x,tc_sockhandle))
  91. #define NSOCKHANDLEP(x) (NTYPEP(x,tc_sockhandle))
  92.  
  93. void mark_sockhandle(SCM handle)
  94. {
  95. }
  96.  
  97. void free_sockhandle(SCM handle)
  98. {
  99.     struct socket_handle *sh;
  100.     sh = SOCKHANDLE(handle);
  101.     if(sh->hostname) free(sh->hostname);
  102.     close(sh->handle);
  103.     free(sh);
  104.     LSOCKHANDLE(handle) = NULL;
  105. }
  106.  
  107. void displ_sockhandle(SCM handle, FILE *f, int mode)
  108. {
  109.     struct socket_handle *sh;
  110.     sh = SOCKHANDLE(handle);
  111.     sprintf(tkbuffer, "#[socket-handle %s %i]", sh->hostname, sh->portnum);
  112.     Puts(tkbuffer,f);
  113. }
  114.     
  115.  
  116. static SCM makesp(int s, char *hn, int portnum)
  117. {
  118.     int t;
  119.     int hnlen;
  120.     FILE *fs, *ft;
  121.     SCM zs, zt;
  122.     long flag;
  123.     
  124.     flag = no_interrupt(1);
  125.  
  126.     t = dup(s); /* duplicate handles so that we are able to access one socket channel */
  127.             /* via two scheme ports */
  128.     if(!((fs = fdopen(s, "r")) && (ft = fdopen(s, "w"))))
  129.         err("internal(makesp): cannot create ports", NIL);
  130.     NEWCELL(zs, tc_iport); 
  131.     NEWCELL(zt, tc_oport);
  132.     zs->storage_as.port.f = fs; setbuf(fs, NULL);  /* unbuffered input/output */
  133.     zt->storage_as.port.f = ft; setbuf(ft, NULL);
  134.     zs->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
  135.     sprintf(zs->storage_as.port.name, "%s:%i(r)", hn, portnum);
  136.     zt->storage_as.port.name = (char*)must_malloc((hnlen = strlen(hn))+16);
  137.     sprintf(zt->storage_as.port.name, "%s:%i(w)", hn, portnum);
  138.     
  139.     no_interrupt(flag);
  140.     return(cons(zs, cons(zt, NIL)));
  141. }    
  142.  
  143. PRIMITIVE prepare_server_socket(SCM portnum)
  144. {
  145.     struct sockaddr_in sin;
  146.     int s;
  147.     long flag;
  148.     SCM ys;
  149.  
  150.     if(NINTEGERP(portnum)) 
  151.         err("not a port number", portnum);
  152.     sin.sin_port = INTEGER(portnum);
  153.     sin.sin_addr.s_addr = INADDR_ANY;
  154.     if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  155.         err(sys_errlist[errno], portnum);
  156.     if(bind(s, (struct sockaddr*)&sin, sizeof sin) < 0)
  157.         switch(errno) {
  158.         case EADDRINUSE:
  159.         case EADDRNOTAVAIL: {
  160.             SCM errcode;
  161.             NEWCELL(errcode, tc_integer);
  162.             SET_INTEGER(errcode, errno);
  163.             return errcode;
  164.         }
  165.         break;
  166.         default: err(sys_errlist[errno], portnum); 
  167.         }
  168.     /* now we're ready to create the object */
  169.     NEWCELL(ys, tc_sockhandle);
  170.     LSOCKHANDLE(ys) = (struct socket_handle*)must_malloc(sizeof (struct socket_handle));
  171.     SOCKHANDLE(ys)->portnum = sin.sin_port;
  172.     SOCKHANDLE(ys)->hostname = (char*)must_malloc(strlen("localhost")+1);
  173.     strcpy(SOCKHANDLE(ys)->hostname, "localhost");
  174.     SOCKHANDLE(ys)->handle = s;
  175.  
  176.     return ys;
  177. }
  178.  
  179.  
  180. PRIMITIVE release_server_socket(SCM handle)
  181. {
  182.     if(NSOCKHANDLEP(handle)) err("not a socket handle", handle);
  183.     close(SOCKHANDLE(handle)->handle);
  184.     return UNDEFINED;
  185. }
  186.  
  187. PRIMITIVE socket_handlep(SCM handle)
  188. {
  189.     return SOCKHANDLEP(handle)? truth: ntruth;
  190. }
  191.  
  192. PRIMITIVE listen_socket(SCM handle)
  193. {
  194.     if(NSOCKHANDLEP(handle)) 
  195.         err("not a socket handle", handle);    
  196.     if(listen(SOCKHANDLE(handle)->handle, 5) < 0) 
  197.         err(sys_errlist[errno], handle); 
  198.     return UNDEFINED;
  199. }
  200.  
  201. PRIMITIVE accept_connection(SCM handle)
  202. {
  203.     int s;
  204.  
  205.     if(NSOCKHANDLEP(handle))
  206.         err("not a socket handle", handle);    
  207.     if((s = accept(SOCKHANDLE(handle)->handle, NULL, NULL)) < 0)
  208.         err(sys_errlist[errno], handle); 
  209.     return makesp(s, SOCKHANDLE(handle)->hostname, SOCKHANDLE(handle)->portnum);
  210. }
  211.  
  212. PRIMITIVE open_client_socket(SCM hostname, SCM portnum)
  213. {
  214.     char *hn;
  215.     struct hostent *hp;
  216.     struct sockaddr_in server;
  217.     int s;
  218.  
  219.     if(NSTRINGP(hostname)) err("bad hostname", hostname);
  220.     if(NINTEGERP(portnum)) err("bad port number", portnum);
  221.     hp = gethostbyname(hn = CHARS(hostname));
  222.     if(!hp) err("unknown or misspelled host name", hostname);
  223.     bzero((char*)&server,sizeof server);
  224.     bcopy(hp->h_addr,(char*)&server.sin_addr, hp->h_length);
  225.     server.sin_family = hp->h_addrtype;
  226.     server.sin_port = INTEGER(portnum);
  227.     if((s = socket(AF_INET,SOCK_STREAM,0)) < 0) 
  228.         err(sys_errlist[errno], NIL);
  229.     if(connect(s, (struct sockaddr *)&server, sizeof server) < 0)
  230.         switch(errno) {
  231.         case EADDRINUSE:
  232.         case EADDRNOTAVAIL:
  233.         case ETIMEDOUT:
  234.         case ECONNREFUSED: {
  235.             SCM errcode;
  236.             NEWCELL(errcode, tc_integer);
  237.             SET_INTEGER(errcode, errno);
  238.             return errcode;
  239.         }
  240.         break;
  241.         default: err(sys_errlist[errno], NIL);
  242.         }
  243.     return makesp(s, hn, server.sin_port);
  244. }
  245.  
  246. PRIMITIVE shutdown_connection(SCM skt)
  247. {
  248.     if(NIPORTP(skt) && NOPORTP(skt)) 
  249.         err("not a port", skt);
  250.     if(shutdown(fileno(skt->storage_as.port.f), IPORTP(skt)?0:1) < 0) 
  251.         err(sys_errlist[errno], NIL);
  252.     return UNDEFINED;
  253. }
  254.  
  255. void init_socket(void)
  256. {
  257.     tc_sockhandle = add_new_type(&sockhandle_type);
  258.  
  259.     add_new_primitive("prepare-server-socket", tc_subr_1,        prepare_server_socket);
  260.     add_new_primitive("release-server-socket!", tc_subr_1,        release_server_socket);
  261.     add_new_primitive("socket-handle?",       tc_subr_1,        socket_handlep);
  262.     add_new_primitive("listen-socket!",        tc_subr_1,        listen_socket);
  263.     add_new_primitive("accept-connection",     tc_subr_1,        accept_connection);
  264.     add_new_primitive("open-client-socket",    tc_subr_2,        open_client_socket);
  265.     add_new_primitive("shutdown-connection!",  tc_subr_1,        shutdown_connection);
  266. };
  267.  
  268.